package org.springframework.context.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * 抽象应用上下文
 * 封装了创建工厂获取bean创建所有的bean等应用上下文的基本方法
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    //转换器的bean名称
    public static final String CONVERSION_SERVICE_BEAN_NAME = "conversionService";


    //容器事件的广播器
    private ApplicationEventMulticaster applicationEventMulticaster;

    /**
     * 该方法用来刷新容器，也像是重新初始化
     *
     * @throws BeansException
     */
    @Override
    public void refresh() throws BeansException {
        //创建bean工厂，并且加载bean定义对象
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        //添加ApplicationContextAwareProcessor，让继承自ApplicationContextAware的bean能感知bean
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        //在bean实例化之前，执行BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);

        //在实例化bean之前 需要先添加bean后处理器 要先一步创建该对象并添加到处理器列表里
        registerBeanPostProcessors(beanFactory);

        //初始化事件的广播器
        initApplicationEventMulticaster();

        //注册监听器
        registerListeners();

        //注册类型转换器和提前实例化单例bean
        finishBeanFactoryInitialization(beanFactory);

        //发布容器刷新的事件
        finishRefresh();
    }

    /**
     * 注册类型转换器并且实例化bean
     * @param beanFactory
     */
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        //设置类型转换器
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
            Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
            if (conversionService instanceof ConversionService) {
                beanFactory.setConversionService((ConversionService) conversionService);
            }
        }

        //提前实例化单例bean
        beanFactory.preInstantiateSingletons();
    }

    /**
     * 执行bean工厂的bean工厂后处理器列表的方法
     *
     * @param beanFactory
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //getBean的方法 就会自动创建没有在单例池里的bean了
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap =
                beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);

        //BeanFactoryPostProcessor是修改bean工厂里的bean定义对象的 所以要传递bean工厂过来
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 注册BeanPostProcessors
     *
     * @param beanFactory
     */
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //getBean的方法 就会自动创建没有在单例池里的bean了
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);

        //BeanPostProcessor是被bean工厂内部在初始化bean的时候调用的 所以需要传递给bean工厂 使其自行调用
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * 初始化事件广播器
     */
    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        //将事件广播器放入单例池里
        beanFactory.addSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }


    /**
     * 注册事件监听器列表
     */
    protected void registerListeners() {
        //根据监听器的接口类型获取所有的监听器，获取的时候 没有的bean会被创建的
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener applicationListener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(applicationListener);
        }
    }

    /**
     * 发布容器刷新完成的事件
     */
    protected void finishRefresh(){
        publishEvent(new ContextRefreshedEvent(this));
    }

    /**
     * 实现发布事件的接口
     * @param event
     */
    @Override
    public void publishEvent(ApplicationEvent event) {
        //发布事件其实就是把事件 交给事件广播器 来分配给对于的监听器
        applicationEventMulticaster.multicastEvent(event);
    }


    @Override
    public boolean containsBean(String name) {
        return getBeanFactory().containsBean(name);
    }
    /**
     * 创建bean工厂，并加载BeanDefinition
     *
     * @throws BeansException
     */
    protected abstract void refreshBeanFactory() throws BeansException;

    /**
     * 获取创建好的bean工厂
     *
     * @return
     */
    public abstract ConfigurableListableBeanFactory getBeanFactory();


    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    /**
     * 提供给调用者调用的直接关闭函数
     */
    @Override
    public void close() {
        doClose();
    }


    /**
     * 提供给调用者异步关闭的注册钩子函数
     */
    @Override
    public void registerShutdownHook() {
        //TODO 注册钩子是干啥。。。
        Thread shutdownHook = new Thread() {
            @Override
            public void run() {
                doClose();
            }
        };

        Runtime.getRuntime().addShutdownHook(shutdownHook);
    }

    protected void doClose() {
        //发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));

        //执行单例bean的销毁方法
        destroyBeans();
    }

    /**
     * 获取工厂 工厂里存有销毁bean集合来销毁bean
     */
    protected void destroyBeans() {
        getBeanFactory().destroySingletons();
    }
}
